package ChatLogic;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;

public class SendFile {

    ArrayList<Socket> sockets = new ArrayList<>();
    private final int BUFFER_SIZE = 65535;
    private int frameNr = 0;
    int frameSize = 65535 / 5;
    private File fileToSend;

    public synchronized void addToSockets(Socket socket) {
        sockets.add(socket);
    }

    public synchronized Socket removeFromSockets(int i) {
        return sockets.remove(i);
    }

    public synchronized int socketSize() {
        return sockets.size();
    }

    public synchronized Socket getSocket() {
        return sockets.get(0);
    }

    private byte[] copyByteArray(byte[] fromArray, byte[] toArray, int fromPosition) {
        for (int i = 0; i < toArray.length; i++) {
            toArray[i] = fromArray[i + fromPosition];
        }
        return toArray;
    }

    class SendFrame implements Runnable {

        byte[] frameToSend;
        int frameNr;
        Socket socket;

        public SendFrame(byte[] frameToSend, int frameNr) {
            this.frameToSend = frameToSend;
            this.frameNr = frameNr;
            this.socket = removeFromSockets(0);

        }

        public void run() {

            try {
                DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                dos.writeUTF(frameNr + "");

                byte[] buffer = new byte[BUFFER_SIZE];
                int sent = 0;
                long startTime = System.currentTimeMillis();
                while (sent < frameToSend.length) {
                    // System.out.println(sent+" v s "+frameToSend.length);
                    if ((frameToSend.length - sent) > BUFFER_SIZE) {
                        buffer = copyByteArray(frameToSend, buffer, sent);
                        socket.getOutputStream().write(buffer, 0, BUFFER_SIZE);
                        sent += BUFFER_SIZE;

                        //System.out.println((frameToSend.length - sent));
                    } else {
                        buffer = new byte[(frameToSend.length - sent)];
                        buffer = copyByteArray(frameToSend, buffer, sent);
                        socket.getOutputStream().write(buffer, 0, (frameToSend.length - sent));
                        sent += (frameToSend.length - sent);
                        break;
                    }
                }
                long endTime = System.currentTimeMillis();
                System.out.println("Frame" + frameNr + "(" + sent + ")" + "  sent in  " + (endTime - startTime) + " ms.");

            } catch (IOException ex) {
                Logger.getLogger(SendFile.class.getName()).log(Level.SEVERE, null, ex);
            }
            addToSockets(socket);
        }
    }

    public SendFile(String ip, int port, int nrOfSockets) { //må legge til ny socket, evt ny socket i User kallt fileTransferSocket eller no, fileToSend hentes fra fileChooser
        JFileChooser fileChooser = new JFileChooser();
        int returnVal = fileChooser.showOpenDialog(null);
        if(returnVal == JFileChooser.APPROVE_OPTION) fileToSend=fileChooser.getSelectedFile();
        Long fileSize = fileToSend.length();
        long sent = 0;

        try {
            Socket communicationSocket = new Socket(ip, port);
            DataOutputStream dos = new DataOutputStream(communicationSocket.getOutputStream());
            DataInputStream dis = new DataInputStream(communicationSocket.getInputStream());
            dos.writeUTF("sendcom");
            dos.writeUTF(fileToSend.getName() + "/*/" + fileToSend.length() + "/*/" + frameSize + "/*/" + nrOfSockets);
            FileInputStream fileInputStream = new FileInputStream(fileToSend);

            for (int i = 0; i < nrOfSockets; i++) {
                Socket sendSocket=new Socket(ip, port);
                new DataOutputStream(sendSocket.getOutputStream()).writeUTF("sendsocket");
                sockets.add(sendSocket);
                sockets.get(i).setPerformancePreferences(0, 1, 3);
                sockets.get(i).setTcpNoDelay(true);
                sockets.get(i).setSendBufferSize(10000);

            }
            System.out.println(fileToSend.getName());
            dis.readUTF().equals("READY");
            Long startTime = System.currentTimeMillis();
            System.out.println("starter sockettransfer");
            System.out.println("size=" + fileSize + " sent= " + sent + " framesize= " + frameSize);
            byte[] frameToSend;
            while ((fileSize - sent) > frameSize) {

                if (socketSize() > 0) {
                    frameToSend = new byte[frameSize];
                    fileInputStream.read(frameToSend, 0, frameSize);
                    new Thread(new SendFrame(frameToSend, frameNr)).start();
                    frameNr += 1;
                    sent += frameSize;
                }
            }
            Long lastFrameSize = fileSize - sent;
            while (true) {
                if (socketSize() > 0) {
                    frameToSend = new byte[lastFrameSize.intValue()];
                    fileInputStream.read(frameToSend, 0, lastFrameSize.intValue());
                    SendFrame sendFrame = new SendFrame(frameToSend, frameNr); //siste sender f;
                    new Thread(sendFrame).start();

                    break;
                }
            }

            System.out.println(new DataInputStream(communicationSocket.getInputStream()).readUTF());
            for (int i = 0; i < sockets.size(); i++) {
                sockets.get(i).close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        new SendFile("localhost", 10823, 4); //84.202.93.112

    }
}
